from character_analyze import Lexical
from character_analyze import Fam
class Syntax:
    aheadp = 0
    row = 0 #记录当前程序所在行数
    def __init__(self, codes):
        self.codes = codes
        self.codes.append(('#', '#'))
    def getsym(self):
        while True:
            if self.codes[self.aheadp] == '\n': #如果是换行符,行数+1
                self.aheadp += 1
                self.row += 1
                continue
            else:
                self.aheadp += 1
                return self.codes[self.aheadp - 1] #返回指针指向的当前值
    def recall(self): #指针回溯
        self.aheadp -= 1
        while self.codes[self.aheadp - 1] == '\n':
            self.aheadp -= 1
            self.row -= 1
        return self.codes[self.aheadp - 1]
    def relocat(self, position, row): #根据位置重新定位指针
        self.aheadp = position
        self.row = row
        self.sym = self.codes[self.aheadp - 1]
    def main(self):
        self.sym = self.getsym()
        self.start() #第一个非终结符
        if self.sym == ('#', '#'):
            print('Finish analyze')
        else:
            print(self.sym)
            raise Exception("Sytax Error")
    def start(self): #程序开始
        self.Z()
        while self.sym[1] == 'main' or self.sym[0] == 0:
            self.Z()
    def Z(self): #声明语句或函数
        if self.sym[0] == 0:
            position = self.aheadp
            row = self.row
            try:
                self.declare()
            except:
                self.relocat(position, row)
                self.func()
        elif self.sym[1] == 'main':
            self.manfunc()
    def declare(self): #全局变量
        self.C()
        self.D()
        if self.sym[0] == ';':
            self.sym = self.getsym()
        else:
            if self.sym[1] == '_':
                raise Exception("[Sytax Error] expected {} before {} on line {}".format('\';\'',self.sym[0], self.row))
            else:
                raise Exception("[Sytax Error] expected {} before {} on line {}".format('\';\'',self.sym[1], self.row))
    def func(self): #函数
        self.C()
        self.E()
        if self.sym[0] == '(':
            self.sym = self.getsym()
            self.params()
            if self.sym[0] == ')':
                self.sym = self.getsym()
                self.block()
            else:
                if self.sym[1] == '_':
                    raise Exception("[Sytax Error] expected declaration specifiers or \'...\' before {} token on line {}".format(self.sym[0], self.row))
                else:
                    raise Exception("[Sytax Error] expected declaration specifiers or \'...\' before {} token on line {}".format(self.sym[1], self.row))
        else:
            if self.sym[1] == '_':
                raise Exception("[Sytax Error] expected {} before {} token on line {}".format('(', self.sym[0], self.row))
            else:
                raise Exception("[Sytax Error] expected {} before {} token on line {}".format('(', self.sym[1], self.row))
    def params(self): #函数形参列表
        self.C()
        self.E()
        while self.sym[0] == ',':
            self.sym = self.getsym()
            self.C()
            self.E()
        else:
            if self.sym[0] != ')': # follow ) 用空推导 
                raise Exception("[Sytax Error] expected {} on line {}".format('\')\'',self.row))
    def manfunc(self): #主函数
        if self.sym[1] == 'main':
            self.sym = self.getsym()
            if self.sym[0] == '(':
                self.sym = self.getsym()
                if self.sym[0] == ')':
                    self.sym = self.getsym()
                    self.block()
                else:
                    raise Exception("[Sytax Error] expected {} at the end of input on line {}".format('\')\'', self.row))
            else:
                raise Exception("[Sytax Error] expected {} at the end of input on line {}".format('\'(\'', self.row))
        else:
            raise Exception("[Sytax Error] undefined reference to {} on line {}".format('WinMain', self.row))
    def block(self): #块内代码
        if self.sym[0] == '{':
            self.sym = self.getsym()
            self.A()
            if self.sym[0] == '}':
                self.sym = self.getsym()
            else:
                raise Exception("[Sytax Error] expected {} at the end of input on line {}".format('\'}\'',self.row))
        else:
            raise Exception("[Sytax Error] expected identifier or {} before {} token on line {}".format('\'{\'','\'}\'',self.row))
    def A(self): #子程序
        if self.sym[0] == 0:#求First(A)
            self.B()
            self.L()
        else:
            self.L()
    def B(self): #变量说明部分
        self.C()
        self.D()
        if self.sym[0] == ';':
            self.sym = self.getsym()
            while self.sym[0] == 0:
                self.C()
                self.D()
                if self.sym[0] == ';':
                    self.sym = self.getsym()
                else:
                    raise Exception("[Sytax Error] expected {} before {} token on line {}".format('\';\'',self.sym[0],self.row))  
        else:
            if self.sym[1] == '_':
                raise Exception("[Sytax Error] expected {} before {} token on line {}".format('\';\'',self.sym[0],self.row))    
            else:
                raise Exception("[Sytax Error] expected {} before {} token on line {}".format('\';\'',self.sym[1],self.row)) 
    def C(self): #变量说明.
        if self.sym[0] == 0:
            self.sym = self.getsym()   
        else:
            raise Exception("[Sytax Error] {} was not declared in this scope on line {}".format(self.sym[1],self.row))
    def D(self): #标识符表
        self.E()
        while self.sym[0] == ',':
            self.sym = self.getsym()
            self.E()          
    def E(self): #标识符
        if self.sym[0] == 'id':
            self.sym = self.getsym()
        else:
            raise Exception("[Sytax Error] declaration does not declare anything on line {}".format(self.row))
    def L(self): #语句块
        if self.sym[0] != '}':
            self.S()
            self.L()
    def S(self): #语句
        if self.sym[0] == 'id': #可能是标号： 或者表达式语句 或者函数调用语句
            islabel = True #暂时认为是标号语句
            position = self.aheadp
            row = self.row
            try:
                self.label()
            except:
                islabel = False
            if islabel:
                self.S()
            else:
                self.relocat(position, row) #回溯
                #是表达式语句
                self.exp()
                if self.sym[0] == ';':
                    self.sym = self.getsym()
                else:
                    if self.sym[1] == '_':
                        raise Exception("[Sytax Error] expexted {} before {} on line {}".format('\';\'',self.sym[0],self.row))
                    else:
                        raise Exception("[Sytax Error] expexted {} before {} on line {}".format('\';\'',self.sym[1],self.row))
        elif self.sym[0] == 5: #控制语句，条件语句
            if self.sym[1] == 'if':
                self.G()
            elif self.sym[1] == 'while':
                self.H()
            elif self.sym[1] == 'for':
                self.I()
            elif self.sym[1] == 'goto':
                self.J()
            elif self.sym[1] == 'break':
                self.K1()
            elif self.sym[1] == 'continue':
                self.K2()
            elif self.sym[1] == 'return':
                self.R()
            else:
                raise Exception("[Sytax Error] Illegal statement {} on line {}".format(self.sym[1],self.row))
        elif self.sym[0] == '{': #块语句
            self.block()
        elif self.sym[0] == ';': #空语句
            self.sym = self.getsym()
        else: #表达式语句
            self.exp()
            if self.sym[0] == ';':
                self.sym = self.getsym()
            else:
                if self.sym[1] == '_':
                    raise Exception("[Sytax Error] expexted {} before {} on line {}".format('\';\'',self.sym[0],self.row))
                else:
                    raise Exception("[Sytax Error] expexted {} before {} on line {}".format('\';\'',self.sym[1],self.row))
    def exp(self): #逗号表达式
        self.exp1()
        while self.sym[0] == ',':
            self.sym = self.getsym()
            self.exp1()
    def exp1(self): #赋值表达式
        if self.sym[0] == 'id':
            self.sym = self.getsym()
            isassign = True
            try:    
                self.assign()
            except:
                isassign = False
            if isassign:
                self.exp1()
            else:
                self.sym = self.recall() #回溯
                self.exp2()
        else:
            self.exp2()
    def exp2(self): #条件表达式
        self.exp3()
        while self.sym[0] == '?':
            self.sym = self.getsym()
            self.exp2()
            if self.sym[0] == ':':
                self.sym = self.getsym()
                self.exp2()
            else:
                raise Exception("[Sytax Error] expected {} on line {}".format('\':\'',self.row))
    def exp3(self): #逻辑或表达式
        self.exp4()
        while self.sym[0] == '||':
            self.sym = self.getsym()
            self.exp4()
    def exp4(self): #逻辑与表达式
        self.exp5()
        while self.sym[0] == '&&':
            self.sym = self.getsym()
            self.exp5()     
    def exp5(self): #等于表达式
        self.exp6()
        while self.sym[0] == '==' or self.sym[0] == '!=':
            self.judge()
            self.exp6()
    def exp6(self): #关系表达式
        self.exp7()
        while self.sym[0] == '<' or self.sym[0] == '>' or self.sym[0] == '<=' or self.sym[0] == '>=':
            self.rela()
            self.exp7()
    def exp7(self): #移位表达式
        self.exp8()
        while self.sym[0] == '>>' or self.sym[0] == '<<':
            self.shift()
            self.exp8()
    def exp8(self): #加法表达式
        self.exp9()
        while self.sym[0] == '+' or self.sym[0] == '-':
            self.coun()
            self.exp9()
    def exp9(self): #乘法表达式
        self.exp10()
        while self.sym[0] == '*' or self.sym[0] == '/' or self.sym[0] == '%':
            self.mul()
            self.exp10()
    def exp10(self): #后++
        position = self.aheadp
        row = self.row
        try:
            self.E()
            self.suffix()
        except:
            self.relocat(position, row) #回溯
            self.exp11()
    def exp11(self):
        if self.sym[0] == '!' or self.sym[0] == '-' :
            self.unary()
            self.exp12()
        elif self.sym[0] == '++' or self.sym[0] == '--' :
            self.suffix()
            self.E()
        else:
            self.exp12()
    def exp12(self): #标识符，括号，常量表达式
        if self.sym[0] == '(':
            self.sym = self.getsym()
            self.exp()
            if self.sym[0] == ')':
                self.sym = self.getsym()
            else:
                raise Exception("[Sytax Error] expected {} before {} on line {}".format('\')\'', self.sym[1], self.row))
        elif self.sym[0] == 'id':
            self.sym = self.getsym()
            if self.sym[0] == '(': #是函数调用表达式
                self.sym = self.getsym()
                self.arglist()
                if self.sym[0] == ')':
                    self.sym = self.getsym()
                else:
                    if self.sym[1] == '_':
                        raise Exception("[Sytax Error] expected expression before {} token on line {}".format(self.sym[0], self.row))
                    else:
                        raise Exception("[Sytax Error] expected expression before {} token on line {}".format(self.sym[1], self.row))
            else: #是标识符表达式
                pass
        elif self.sym[0] == 1: #int
            self.sym = self.getsym()
        elif self.sym[0] == 2: #float
            self.sym = self.getsym()
        elif self.sym[0] == 3: #char
            self.sym = self.getsym()
        elif self.sym[0] == 4: #string
            raise Exception("[Sytax Error] string type is not supported on line {}".format(self.row))
        else:
            print(self.sym)
            raise Exception("[Sytax Error] illegal expression on line {}".format(self.row))
    def arglist(self):
        self.exp1()
        while self.sym[0] == ',':
            self.sym = self.getsym()
            self.exp1()
    def unary(self): #单目运算符
        if self.sym[0] == '!':
            self.sym = self.getsym()
        else: # -
            self.sym = self.getsym()
    def suffix(self): # ++ --
        if self.sym[0] == '++':
            self.sym = self.getsym()
        elif self.sym[0] == '--':
            self.sym = self.getsym()
        else:
            raise Exception("[Sytax Error] illegal expression on line {}".format(self.row))
    def mul(self): #乘法运算符
        if self.sym[0] == '*':
            self.sym = self.getsym()
        elif self.sym[0] == '/':
            self.sym = self.getsym()  
        else: # %
            self.sym = self.getsym()
    def coun(self): #加减运算符
        if self.sym[0] == '+':
            self.sym = self.getsym()
        else: # -
            self.sym = self.getsym()
    def shift(self): #移位运算符
        if self.sym[0] == '>>':
            self.sym = self.getsym()
        else:
            self.sym = self.getsym()
    def rela(self): #关系运算符
        if self.sym[0] == '<':
            self.sym = self.getsym()
        elif self.sym[0] == '>':
            self.sym = self.getsym()
        elif self.sym[0] == '<=':
            self.sym = self.getsym()
        else: #>=
            self.sym = self.getsym()
    def judge(self): #等于运算符
        if self.sym[0] == '==':
            self.sym = self.getsym()
        else: #!=
            self.sym = self.getsym()
    def assign(self): #赋值运算符
        if self.sym[0] == '=':
            self.sym = self.getsym()
        elif self.sym[0] == '+=':
            self.sym = self.getsym()
        elif self.sym[0] == '-=':
            self.sym = self.getsym()
        elif self.sym[0] == '*=':
            self.sym = self.getsym()
        elif self.sym[0] == '/=':
            self.sym = self.getsym()
        elif self.sym[0] == '%=':
            self.sym = self.getsym()
        elif self.sym[0] == '<<=':
            self.sym = self.getsym()
        elif self.sym[0] == '>>=':
            self.sym = self.getsym()
        else:
            raise Exception("[Sytax Error] expected {} before {} on line {}".format('\';\'', self.sym[1], self.row))
    def G(self): #条件语句 if
        if self.sym[1] == 'if':
            self.sym = self.getsym()
            if self.sym[0] == '(':
                self.sym = self.getsym()
                self.exp()
                if self.sym[0] == ')':
                    self.sym = self.getsym()
                    self.S()
                    self.tail()
                else:
                    if self.sym[0] == '_':
                        raise Exception("[Sytax Error] expected {} before {} token on line {}".format('\')\'',self.sym[1], self.row))
                    else:
                        raise Exception("[Sytax Error] expected {} before {} token on line {}".format('\')\'',self.sym[0], self.row))
            else:
                raise Exception("[Sytax Error] expected {} before numeric constant on line {}".format('\'(\'', self.row))
    def tail(self): #else
        if self.sym[1] == 'else':
            self.sym = self.getsym()
            self.S()
    def H(self): #循环语句while
        if self.sym[1] == 'while':
            self.sym = self.getsym()
            if self.sym[0] == '(':
                self.sym = self.getsym()
                self.exp()
                if self.sym[0] == ')':
                    self.sym = self.getsym()
                    self.S()
                else:
                    if self.sym[0] == '_':
                        raise Exception("[Sytax Error] expected {} before {} token on line {}".format('\')\'',self.sym[1], self.row))
                    else:
                        raise Exception("[Sytax Error] expected {} before {} token on line {}".format('\')\'',self.sym[0], self.row))
            else:
                raise Exception("[Sytax Error] expected {} before numeric constant on line {}".format('\'(\'', self.row))
        pass
    def I(self): #循环语句for
        if self.sym[1] == 'for':
            self.sym = self.getsym()
            if self.sym[0] == '(':
                self.sym = self.getsym()
                self.exp()
                if self.sym[0] == ';':
                    self.sym = self.getsym()
                    self.exp()
                    if self.sym[0] == ';':
                        self.sym = self.getsym()
                        self.exp()
                        if self.sym[0] == ')':
                            self.sym = self.getsym()
                            self.block()
                        else:
                            if self.sym[0] == '_':
                                raise Exception("[Sytax Error] expected {} before {} token on line {}".format('\')\'',self.sym[1], self.row))
                            else:
                                raise Exception("[Sytax Error] expected {} before {} token on line {}".format('\')\'',self.sym[0], self.row))
                    else:
                        if self.sym[0] == '_':
                            raise Exception("[Sytax Error] expected {} before {} on line {}".format('\';\'',self.sym[1], self.row))
                        else:
                            raise Exception("[Sytax Error] expected {} before {} on line {}".format('\';\'',self.sym[0], self.row))
                else:
                    if self.sym[0] == '_':
                        raise Exception("[Sytax Error] expected {} before {} on line {}".format('\';\'',self.sym[1], self.row))
                    else:
                        raise Exception("[Sytax Error] expected {} before {} on line {}".format('\';\'',self.sym[0], self.row))
            else:
                if self.sym[0] == '_':
                    raise Exception("[Sytax Error] expected {} before {} on line {}".format('\'(\'',self.sym[1], self.row))
                else:
                    raise Exception("[Sytax Error] expected {} before {} on line {}".format('\'(\'',self.sym[0], self.row))
    def J(self): #goto
        if self.sym[1] == 'goto':
            self.sym = self.getsym()
            self.E()
            if self.sym[0] == ';':
                self.sym = self.getsym()
            else:
                if self.sym[0] == '_':
                    raise Exception("[Sytax Error] expected {} before {} on line {}".format('\';\'',self.sym[1], self.row))
                else:
                    raise Exception("[Sytax Error] expected {} before {} on line {}".format('\';\'',self.sym[0], self.row))                
    def K1(self): #break
        if self.sym[1] == 'break':
            self.sym = self.getsym()
            if self.sym[0] == ';':
                self.sym = self.getsym()
            else:
                if self.sym[0] == '_':
                    raise Exception("[Sytax Error] expected {} before {} on line {}".format('\';\'',self.sym[1], self.row))
                else:
                    raise Exception("[Sytax Error] expected {} before {} on line {}".format('\';\'',self.sym[0], self.row))
    def K2(self): #continue
        if self.sym[1] == 'continue':
            self.sym = self.getsym()
            if self.sym[0] == ';':
                self.sym = self.getsym()
            else:
                if self.sym[0] == '_':
                    raise Exception("[Sytax Error] expected {} before {} on line {}".format('\';\'',self.sym[1], self.row))
                else:
                    raise Exception("[Sytax Error] expected {} before {} on line {}".format('\';\'',self.sym[0], self.row))        
    def R(self): #控制语句return
        if self.sym[1] == 'return':
            self.sym = self.getsym()
            self.exp()
            if self.sym[0] == ';':
                self.sym = self.getsym()
            else:
                if self.sym[0] == '_':
                    raise Exception("[Sytax Error] expected {} before {} on line {}".format('\';\'',self.sym[1], self.row))
                else:
                    raise Exception("[Sytax Error] expected {} before {} on line {}".format('\';\'',self.sym[0], self.row))
    def label(self): #标号语句
        if self.sym[0] == 'id':
            self.sym = self.getsym()
            if self.sym[0] == ':':
                self.sym = self.getsym()
            else:
                raise Exception("[Sytax Error] {} undeclared on line {}".format(self.sym[1],self.row))
fam = Fam()
fam.main()
synax = Syntax(fam.output)
synax.main()

